package cn.edu.jsu.zjj.model.utils;

import cn.edu.jsu.zjj.model.dto.user.UserFillRequest;
import cn.edu.jsu.zjj.model.entity.UserTitle;
import cn.edu.jsu.zjj.model.entity.UserWork;
import com.microsoft.schemas.office.word.STWrapType;
import org.apache.poi.util.Units;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.xmlbeans.SchemaType;
import org.apache.xmlbeans.XmlException;
import org.openxmlformats.schemas.drawingml.x2006.main.CTBlipFillProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.CTGraphicalObject;
import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D;
import org.openxmlformats.schemas.drawingml.x2006.picture.CTPicture;
import org.openxmlformats.schemas.drawingml.x2006.picture.CTPictureNonVisual;
import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTAnchor;
import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTInline;
import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTWrapSquare;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTDrawing;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.List;

public class DocxUtils {
    public static void modifyDocx(HttpServletResponse response, UserFillRequest userFillRequest) throws Exception {
        Map<String, Object> map = new HashMap<>();

        map.put("#{name}", userFillRequest.getUser() != null ? userFillRequest.getUser().getName() : "");
        map.put("#{sex}", userFillRequest.getUser() != null && userFillRequest.getUser().getSex() != null ? (Objects.equals(userFillRequest.getUser().getSex(), "0") ? "男" : "女") : "");
        map.put("#{nationality}", userFillRequest.getUser() != null ? userFillRequest.getUser().getNationality() : "");
        map.put("#{birthday}", userFillRequest.getUser() != null && userFillRequest.getUser().getBirthday() != null ? (userFillRequest.getUser().getBirthday().getYear() + "." + (userFillRequest.getUser().getBirthday().getMonth().getValue())) : "");
        map.put("#{address}", userFillRequest.getUser() != null ? userFillRequest.getUser().getAddress() : "");
        map.put("#{political_status}", userFillRequest.getUser() != null ? userFillRequest.getUser().getPoliticalStatus() : "");
        map.put("#{post}", userFillRequest.getUser() != null ? userFillRequest.getUser().getPost() : "");
        map.put("#{teaching_subjects}", userFillRequest.getUser() != null ? userFillRequest.getUser().getTeachingSubjects() : "");
        map.put("#{entry_time}", userFillRequest.getUser() != null && userFillRequest.getUser().getEntryTime() != null ? (userFillRequest.getUser().getEntryTime().getYear() + "." + (userFillRequest.getUser().getEntryTime().getMonth().getValue())) : "");
        map.put("#{title}", userFillRequest.getTitle() != null ? userFillRequest.getTitle() : "");
        map.put("#{obtain_time}", userFillRequest.getObtainDate() != null ? (userFillRequest.getObtainDate().getYear() + "." + (userFillRequest.getObtainDate().getMonth().getValue())) : "");
        map.put("#{degree}", userFillRequest.getUser() != null ? userFillRequest.getUser().getDegree() : "");
        map.put("#{academic_degree}", userFillRequest.getUser() != null ? userFillRequest.getUser().getAcademicDegree() : "");

        Date graduationDate = userFillRequest.getUser() != null ? userFillRequest.getUser().getGraduationDate() : null;
        LocalDateTime now = graduationDate != null ? graduationDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime() : null;
        map.put("#{more}", now != null ? (now.getYear() + "." + (now.getMonth().getValue()) + " " + userFillRequest.getUser().getAlmaMater() + " " + userFillRequest.getUser().getMajor()) : "");

        map.put("#{type}", userFillRequest.getUser() != null ? userFillRequest.getUser().getType() : "");
        map.put("#{sideline}", userFillRequest.getUserWorks() != null && !userFillRequest.getUserWorks().isEmpty() ? userFillRequest.getUserWorks().get(0).getSideline() : "");
        map.put("#{mail_address}", userFillRequest.getUser() != null ? userFillRequest.getUser().getMailAddress() : "");
        map.put("#{phone_number}", userFillRequest.getUser() != null ? userFillRequest.getUser().getPhoneNumber() : "");
        map.put("#{wx_number}", userFillRequest.getUser() != null ? userFillRequest.getUser().getWxNumber() : "");
        map.put("#{qq}", userFillRequest.getUser() != null ? userFillRequest.getUser().getQq() : "");
        List<UserWork> userWorks = userFillRequest.getUserWorks();
        if (userWorks != null && !userWorks.isEmpty()) {
            UserWork firstWork = userWorks.get(0);
            map.put("#{start_date}", firstWork.getStartDate() != null ? (firstWork.getStartDate().getYear() + "." + firstWork.getStartDate().getMonth().getValue()) : "");
            map.put("#{end_date}", firstWork.getEndDate() != null ? (firstWork.getEndDate().getYear() + "." + firstWork.getEndDate().getMonth().getValue()) : "");
            map.put("#{description}", firstWork.getDescription());
            map.put("#{cert}", firstWork.getCertifier());
        } else {
            map.put("#{start_date}", "");
            map.put("#{end_date}", "");
            map.put("#{description}", "");
            map.put("#{cert}", "");
        }


        String url = "https://hmleadnews5283.oss-cn-beijing.aliyuncs.com/教师基本情况登记表-1731528586310.docx";
        int lastSlashIndex = url.lastIndexOf("/");
        String newFileName = "";
        String fileName = url.substring(lastSlashIndex + 1);
        int lastDashIndex = fileName.lastIndexOf("-");
        newFileName = fileName.substring(0, lastDashIndex) + ".docx";


        ZipUtils.urlToByte(url);
        byte[] data = ZipUtils.urlBytes;
        ByteArrayInputStream fis = new ByteArrayInputStream(data);
        XWPFDocument document = new XWPFDocument(fis);

        // 替换段落中的文本
        for (XWPFParagraph paragraph : document.getParagraphs()) {
            for (XWPFRun run : paragraph.getRuns()) {
                replace(map, run);
            }
        }

        // 替换表格中的文本
        for (XWPFTable table : document.getTables()) {
            for (XWPFTableRow row : table.getRows()) {
                for (XWPFTableCell cell : row.getTableCells()) {
                    for (XWPFParagraph paragraph : cell.getParagraphs()) {
                        for (XWPFRun run : paragraph.getRuns()) {
                            paragraph.setWordWrapped(true);
                            replace(map, run);
                        }
                    }
                }
            }
        }

        // 插入图片
        String avatarUrl = userFillRequest.getUser().getAvatar();
        if (avatarUrl != null && !avatarUrl.isEmpty()) {
            try (InputStream avatarInputStream = new URL(avatarUrl).openStream()) {
                int pictureType = XWPFDocument.PICTURE_TYPE_JPEG;
                if (avatarUrl.endsWith(".png")) {
                    pictureType = XWPFDocument.PICTURE_TYPE_PNG;
                }
                if (avatarUrl.endsWith(".gif")) {
                    pictureType = XWPFDocument.PICTURE_TYPE_GIF;
                }
                if (avatarUrl.endsWith(".bmp")) {
                    pictureType = XWPFDocument.PICTURE_TYPE_BMP;
                }
                String fileNamePrefix = "avatar";
                int width = 260; // 图片宽度
                int height = 350; // 图片高度

                for (XWPFTable table : document.getTables()) {
                    for (XWPFTableRow row : table.getRows()) {
                        for (XWPFTableCell cell : row.getTableCells()) {
                            for (XWPFParagraph paragraph : cell.getParagraphs()) {
                                paragraph.setWordWrapped(true);
                                for (XWPFRun run : paragraph.getRuns()) {
                                    String text = run.getText(0);
                                    if (text != null && text.equals("#{avatar}")) {
                                        run.setText("", 0);
                                        XWPFPicture picture = run.addPicture(avatarInputStream, pictureType, fileNamePrefix, Units.toEMU(width), Units.toEMU(height));
                                        // 2. 获取到图片数据
                                        CTDrawing drawing = run.getCTR().getDrawingArray(0);
                                        CTGraphicalObject graphicalObject = drawing.getInlineArray(0).getGraphic();

                                        //拿到新插入的图片替换添加CTAnchor 设置浮动属性 删除inline属性
                                        CTAnchor anchor = getAnchorWithGraphic(graphicalObject, "TEST1",
                                                Units.pixelToEMU(144), Units.pixelToEMU(192),//图片大小
                                                Units.toEMU(1), Units.toEMU(9), false);//相对当前段落位置 需要计算段落已有内容的左偏移
                                        drawing.setAnchorArray(new CTAnchor[]{anchor});//添加浮动属性
                                        drawing.removeInline(0);
                                        break;
                                    }
                                }
                            }
                        }
                    }
                }
            } catch (IOException e) {
                throw new RuntimeException("Failed to open or read avatar input stream", e);
            }
        }


        File tempFile = File.createTempFile("temp", ".docx");
        try (FileOutputStream fos = new FileOutputStream(tempFile)) {
            document.write(fos);
        } catch (IOException e) {
            throw new RuntimeException("Failed to write document to temporary file", e);
        }
        byte[] Docudata = convertFileToByteArray(tempFile);
        send(Docudata, response, newFileName);

//        // 保存到临时文件
//        Path tempFilePath = Files.createTempFile("temp", ".docx");
//        try (FileOutputStream fos = new FileOutputStream(tempFilePath.toFile())) {
//            document.write(fos);
//        }
//
//        // 将临时文件读取为字节数组
//        byte[] docData = Files.readAllBytes(tempFilePath);
//
//        // 发送文件
//        send(docData, response, fileName);
    }

    private static void replace(Map<String, Object> map, XWPFRun run) {
        String text = run.getText(0);
        if (text != null) {
            for (Map.Entry<String, Object> entry : map.entrySet()) {
                if (entry.getValue() != null){
                    text = text.replace(entry.getKey(), entry.getValue().toString());
                } else{
                    text = text.replace(entry.getKey(), "");
                }
            }
            run.setText(text, 0);
        }
    }

    public static byte[] convertFileToByteArray(File file) throws IOException {
        try (FileInputStream fis = new FileInputStream(file); ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = fis.read(buffer)) != -1) {
                bos.write(buffer, 0, bytesRead);
            }
            return bos.toByteArray();
        }
    }


    private static void send(byte[] docxData, HttpServletResponse response, String fileName) throws IOException {
        // 编码文件名以适应不同浏览器
        String encodedFileName = new String(fileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);

        // 设置响应内容类型为 DOCX 格式
        response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");

        // 对于支持 RFC 5987 的浏览器
        if (ZipUtils.isRFC5987Supported(response)) {
            response.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + URLEncoder.encode(fileName, "UTF-8"));
        } else {
            // 对于不支持 RFC 5987 的老版本浏览器（如 IE），提供备选方案
            response.setHeader("Content-Disposition", "attachment; filename=" + fileName);
        }

        // 获取响应的输出流
        OutputStream outputStream = response.getOutputStream();

        // 将 DOCX 数据写入输出流
        outputStream.write(docxData);

        // 刷新输出流，确保所有数据都被写出
        outputStream.flush();

        // 关闭输出流
        outputStream.close();
    }


    /**
     * @param ctGraphicalObject 图片数据
     * @param deskFileName      图片描述
     * @param width             宽
     * @param height            高
     * @param leftOffset        水平偏移 left
     * @param topOffset         垂直偏移 top
     * @param behind            文字上方，文字下方
     * @return
     * @throws Exception
     */
    public static CTAnchor getAnchorWithGraphic(CTGraphicalObject ctGraphicalObject,
                                                String deskFileName, int width, int height,
                                                int leftOffset, int topOffset, boolean behind) {
        String anchorXML =
                "<wp:anchor xmlns:wp=\"http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing\" "
                        + "simplePos=\"0\" relativeHeight=\"0\" behindDoc=\"" + ((behind) ? 1 : 0) + "\" locked=\"0\" layoutInCell=\"1\" allowOverlap=\"1\">"
                        + "<wp:simplePos x=\"0\" y=\"0\"/>"
                        + "<wp:positionH relativeFrom=\"column\">"
                        + "<wp:posOffset>" + leftOffset + "</wp:posOffset>"
                        + "</wp:positionH>"
                        + "<wp:positionV relativeFrom=\"paragraph\">"
                        + "<wp:posOffset>" + topOffset + "</wp:posOffset>" +
                        "</wp:positionV>"
                        + "<wp:extent cx=\"" + width + "\" cy=\"" + height + "\"/>"
                        + "<wp:effectExtent l=\"0\" t=\"0\" r=\"0\" b=\"0\"/>"
                        + "<wp:wrapNone/>"
                        + "<wp:docPr id=\"1\" name=\"Drawing 0\" descr=\"" + deskFileName + "\"/><wp:cNvGraphicFramePr/>"
                        + "</wp:anchor>";

        CTDrawing drawing = null;
        try {
            drawing = CTDrawing.Factory.parse(anchorXML);
        } catch (XmlException e) {
            e.printStackTrace();
        }
        CTAnchor anchor = drawing.getAnchorArray(0);
        anchor.setGraphic(ctGraphicalObject);
        return anchor;
    }

}
